package de.saxsys.projectiler;
import java.text.SimpleDateFormat;
import java.util.Date;
import javafx.animation.Animation.Status;
import javafx.animation.FadeTransitionBuilder;
import javafx.animation.TranslateTransition;
import javafx.animation.TranslateTransitionBuilder;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;
import org.apache.commons.lang3.StringUtils;
import de.saxsys.projectiler.concurrent.CheckInTask;
import de.saxsys.projectiler.concurrent.CheckOutTask;
import de.saxsys.projectiler.concurrent.TimeSpentCountUpThread;
import de.saxsys.projectiler.login.Login;
import de.saxsys.projectiler.misc.DisableSceneOnHalfAnimation;
import de.saxsys.projectiler.misc.MouseEventDistanceChecker;
import de.saxsys.projectiler.misc.Notification;
import de.saxsys.projectiler.misc.ProjectTask;
import de.saxsys.projectiler.misc.UITools;
import de.saxsys.projectiler.tray.Tray;
public class ProjectilerController {
private static final double OPAQUE_VALUE = 0.8;
private static final double VISIBLE_VALUE = 1.0;
private Login login;
@FXML
private StackPane root, timePane;
@FXML
private ImageView timeImage, closeImage;
@FXML
private Label fromTimeLabel, toTimeLabel, timeSpentLabel;
@FXML
private ChoiceBox<String> projectChooser;
private TranslateTransition transition;
private final Projectiler projectiler = Projectiler.createDefaultProjectiler();
private TimeSpentCountUpThread timeSpentCountUpThread;
@FXML
void initialize() {
initLogin();
initTransition();
initProjectChooser();
createListeners();
login();
}
private void initLogin() {
login = new Login(projectiler);
login.loginSucessfulProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(final ObservableValue<? extends Boolean> arg0, final Boolean arg1, final Boolean arg2) {
loggedIn();
fillDropDownWithProjects();
if (projectiler.isCheckedIn()) {
Notification.Notifier.INSTANCE.notifySuccess("Bestehende Buchung",
"Bestehende Buchung wiederhergestellt.");
performCheckIn();
pullCardDown();
}
}
});
}
/**
*
*/
private void initTransition() {
transition =
TranslateTransitionBuilder.create().node(timePane).rate(2).toY(timePane.getLayoutY() + 80)
.autoReverse(true).cycleCount(2).build();
}
/**
*
*/
private void initProjectChooser() {
projectChooser.setItems(FXCollections
.<String> observableArrayList("No project currently laoded - maybe an error occured."));
projectChooser.setOpacity(0.0);
}
/*
* GUI STATES
*/
private void login() {
login.setVisible(true);
root.getChildren().add(login);
UITools.makeInvisible(closeImage);
UITools.hide(projectChooser, timePane, timeImage);
timePane.setMouseTransparent(true);
}
private void loggedIn() {
loadingIndication(false);
login.setVisible(false);
UITools.makeVisible(closeImage);
UITools.hide(fromTimeLabel, toTimeLabel, timeSpentLabel);
UITools.fadeIn(timePane, timeImage);
timePane.setMouseTransparent(false);
root.getChildren().remove(login);
}
/**
* @return if the card could be pulled down
*/
private boolean pullCardDown() {
if (!(transition.getStatus() == Status.RUNNING || transition.getStatus() == Status.PAUSED)) {
transition.currentTimeProperty().addListener(new DisableSceneOnHalfAnimation(transition));
transition.play();
return true;
}
return false;
}
/**
* @return
*
*/
private boolean liftCardUp() {
if (transition.getStatus() == Status.PAUSED) {
transition.play();
return true;
}
return false;
}
/*
* Button handler
*/
private void createListeners() {
new MouseEventDistanceChecker(timePane) {
@Override
public void fire() {
// If a click was performed on the timePane we have to check, whether it was not caused by a drag
if (pullCardDown()) {
performCheckIn();
} else if (liftCardUp()) {
performCheckOut();
}
}
};
}
/*
* Labels
*/
private void displayFromTimeLabel(final Date date) {
if (date == null) {
toTimeLabel.setText("Error");
} else {
final String displayString = new SimpleDateFormat("H:mm").format(date);
fromTimeLabel.setText(displayString);
fromTimeLabel.setOpacity(0.0);
UITools.fadeIn(fromTimeLabel);
}
}
/*
* Labels
*/
private void displayToTimeLabel(final Date date) {
if (date == null) {
toTimeLabel.setText("Error");
} else {
final String displayString = new SimpleDateFormat("H:mm").format(date);
toTimeLabel.setText(displayString);
toTimeLabel.setOpacity(0.0);
UITools.fadeIn(toTimeLabel);
}
}
@FXML
void onCloseButtonClicked(final Event event) {
Tray.getInstance().hideStage();
}
private void fillDropDownWithProjects() {
final ProjectTask projectilerTask = new ProjectTask(projectiler);
projectilerTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(final WorkerStateEvent t) {
projectChooser.getItems().clear();
projectChooser.getItems().addAll(
FXCollections.observableArrayList(projectilerTask.valueProperty().get()));
projectChooser.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(final ObservableValue<? extends String> arg0, final String arg1,
final String arg2) {
if (arg2 != null && !arg2.isEmpty()) {
projectiler.saveProjectName(arg2);
}
}
});
final String projectName = UserDataStore.getInstance().getProjectName();
if (projectName == null) {
projectChooser.getSelectionModel().select(0);
} else {
projectChooser.getSelectionModel().select(projectName);
}
UITools.fadeIn(projectChooser);
}
});
new Thread(projectilerTask).start();
}
private void performCheckIn() {
if (projectiler.isCheckedIn()) {
// Already checked in
final Date startDate = UserDataStore.getInstance().getStartDate();
displayFromTimeLabel(startDate);
startTimeSpentCountUp(startDate);
} else {
final CheckInTask task = new CheckInTask(projectiler);
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(final WorkerStateEvent arg0) {
if (task.getValue() != null) {
displayFromTimeLabel(task.getValue());
startTimeSpentCountUp(task.getValue());
} else {
liftCardUp();
}
}
});
new Thread(task).start();
}
timeSpentLabel.setOpacity(0.2);
UITools.fadeIn(timeSpentLabel);
UITools.hide(toTimeLabel);
}
private void performCheckOut() {
final String projectKey = projectChooser.getSelectionModel().getSelectedItem();
if (StringUtils.isEmpty(projectKey)) {
return;
}
final CheckOutTask task = new CheckOutTask(projectiler, projectKey);
loadingIndication(true);
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(final WorkerStateEvent event) {
if (task.getValue() != null) {
displayToTimeLabel(task.getValue());
}
loadingIndication(false);
// Stop Timer which counted the checkin time
timeSpentCountUpThread.interrupt();
}
});
new Thread(task).start();
}
private void loadingIndication(final boolean enabled) {
double opacity = VISIBLE_VALUE;
if (enabled) {
opacity = OPAQUE_VALUE;
}
final Parent root = timeImage.getScene().getRoot();
root.setMouseTransparent(enabled);
FadeTransitionBuilder.create().toValue(opacity).duration(Duration.seconds(0.5)).node(root).build().play();
}
private void startTimeSpentCountUp(final Date date) {
if (timeSpentCountUpThread != null) {
timeSpentCountUpThread.interrupt();
}
timeSpentCountUpThread = new TimeSpentCountUpThread(timeSpentLabel.textProperty(), date);
UITools.fadeIn(timeSpentLabel);
timeSpentCountUpThread.start();
}
}